package com.lemon.service;

import com.lemon.business.EtlHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author lenomSeven 1337857379@qq.com
 * @date 2020/10/6
 */
public class ServerNetty {
    private static final Logger logger = LoggerFactory.getLogger(ServerNetty.class);

    private int port;

    public ServerNetty(int port){
        this.port = port;
    }

    // netty 服务端启动
    public void start() throws InterruptedException{
        // 用来接收进来的连接
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        // 用来处理已经被接收的连接，一旦bossGroup接收到连接，就会把连接信息注册到workerGroup上
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            // nio服务的启动类
            ServerBootstrap sbs = new ServerBootstrap();
            // 配置nio服务参数
            sbs.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class) // 说明一个新的Channel如何接收进来的连接
                    .option(ChannelOption.SO_BACKLOG, 128) // tcp最大缓存链接个数
                    .childOption(ChannelOption.SO_KEEPALIVE, true) //保持连接
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new HttpServerCodec());
                            socketChannel.pipeline().addLast( new HttpObjectAggregator(65536));
                            socketChannel.pipeline().addLast(new ChunkedWriteHandler());
                            // 网络超时时间
                            socketChannel.pipeline().addLast(new ReadTimeoutHandler(10));
                            // 处理接收到的请求
                            socketChannel.pipeline().addLast(new EtlHandler());
                        }
                    });

            logger.info("server 开启-------- port :{}", port);
            // 绑定端口，开始接受链接
            ChannelFuture cf = sbs.bind(port).sync();
            // 等待服务端口的关闭；在这个例子中不会发生，但你可以优雅实现；关闭你的服务
            cf.channel().closeFuture().sync();
        } finally{
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
            logger.info("server close..");
        }
    }
}